package org.oryxeditor.server;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletOutputStream;

import javax.servlet.ServletContext;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.Deque;
import java.util.LinkedList;
import com.simulario.server.XSLT2ProcessorImpl;

import java.io.*;
import java.net.URI;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Servlet implementation class GenerateZFCode
 */
public class GenerateZFCode extends HttpServlet {
	private static final long serialVersionUID = 2L;
	
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public GenerateZFCode() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
    
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	
    	//get AOR-AppML from POST
    	ServletContext context = getServletContext();
    	String aor = request.getParameter("file");    	
    	
        // create ZF-Implementation-Model
        InputStream transIMLStream = context.getResourceAsStream("/lib/AORML-ZFIML.xsl");
        String transIMLString = getFromStream(transIMLStream);
        
        XSLT2ProcessorImpl pro = new XSLT2ProcessorImpl();
        pro.translate(transIMLString,aor);
        
        //create MySQL-Implementation-Model
        InputStream transSQLStream = context.getResourceAsStream("/lib/AORML-MySQLML.xsl");
        String transSQLString = getFromStream(transSQLStream);
        pro.translate(transSQLString,aor);
        
        //create MySQL-DDL
        InputStream mySQLStream = context.getResourceAsStream("/test/MySQLML.xml");
        String mySQLString = getFromStream(mySQLStream);
        InputStream transDDLStream = context.getResourceAsStream("/lib/MySQLML-SQLDDL.xsl");
        String transDDLString = getFromStream(transDDLStream);
        pro.translate(transDDLString,mySQLString);
        
        //create Zend Framework Application
        InputStream imlStream = context.getResourceAsStream("/test/ZF-IML.xml");
        String imlString = getFromStream(imlStream);
        InputStream transAppStream = context.getResourceAsStream("/lib/ZFIML-ZFApp.xsl");
        String transAppString = getFromStream(transAppStream);
        
        pro.translate(transAppString, imlString);
    	
    	//create Zip-File from created Application-Folder and response
        try {
            
            String frame = getServletContext().getRealPath("frame");
            File framedir = new File(frame);            
            
            String path = getServletContext().getRealPath("test");
            
            File directory = new File(path);
            //copy all not generated Files in output folder
            copyDir(framedir, directory);
            
            File aorFile = new File(path + "/AOR-AppML.xml");
            generateFile(aorFile,aor);
            
            String[] files = directory.list();
            
            //
            // Checks to see if the directory contains some files.
            //
            if (files != null && files.length > 0) {

            	// Packt das Verzeichnis mit Struktur
            	byte[] zip = zip(directory);
            	
            	
                ServletOutputStream sos = response.getOutputStream();
                
                response.setContentType("application/zip");
                String zipname = "data.zip";
                String headerfn = "attachment; filename=\"" + zipname + "\"";
                response.setHeader("Content-Disposition", headerfn);

                sos.write(zip);
                sos.flush();
            }
            cleanDir(directory);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
	
    private byte[] zip(File directory) throws IOException {
        URI base = directory.toURI();
        Deque<File> queue = new LinkedList<File>();
        queue.push(directory);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Closeable res = baos;
        
        try {
          ZipOutputStream zout = new ZipOutputStream(baos);
          res = zout;
          while (!queue.isEmpty()) {
            directory = queue.pop();
            for (File kid : directory.listFiles()) {
              String name = base.relativize(kid.toURI()).getPath();
              if (kid.isDirectory()) {
                queue.push(kid);
                name = name.endsWith("/") ? name : name + "/";
                zout.putNextEntry(new ZipEntry(name));
              } else {
                zout.putNextEntry(new ZipEntry(name));
                copy(kid, zout);
                zout.closeEntry();
              }
            }
          }
        } finally {
            res.close();
        }
        return baos.toByteArray();
    }

    private static void copy(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        while (true) {
            int readCount = in.read(buffer);
            if (readCount < 0) {
                break;
            }
            out.write(buffer, 0, readCount);
        }
    }

     private static void copy(File file, OutputStream out) throws IOException {
        InputStream in = new FileInputStream(file);
        try {
            copy(in, out);
        } finally {
            in.close();
        }
    }
    private static String getFromStream(InputStream stream) throws IOException{
    	final char[] buffer = new char[0x10000];
        StringBuilder out = new StringBuilder();
        Reader in = new InputStreamReader(stream, "UTF-8");
        int read;
        do {
          read = in.read(buffer, 0, buffer.length);
          if (read>0) {
            out.append(buffer, 0, read);
          }
        } while (read>=0);
    	return out.toString();
    }
    private static boolean cleanDir(File dir) {
        String[] children = dir.list();
        for (int i=0; i<children.length; i++) {
            boolean success = recDirDel(new File(dir, children[i]));
            if (!success) {
                return false;
            }
        }
        return true;
    }
    private static boolean recDirDel(File dir) {
        if(dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                boolean success = recDirDel(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // delete empty directory
        return dir.delete();
    }
    private static void copyDir(File source, File target) throws FileNotFoundException, IOException { 
        
        File[] files = source.listFiles(); 
        target.mkdirs(); 
        for (File file : files) { 
            if (file.isDirectory()) { 
                copyDir(file, new File(target.getAbsolutePath() + System.getProperty("file.separator") + file.getName())); 
            } 
            else { 
                copyFile(file, new File(target.getAbsolutePath() + System.getProperty("file.separator") + file.getName())); 
            } 
        } 
    } 
     
    private static void copyFile(File file, File target) throws FileNotFoundException, IOException { 
         
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); 
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(target, true)); 
        int bytes = 0; 
        while ((bytes = in.read()) != -1) { 
            out.write(bytes); 
        } 
        in.close(); 
        out.close(); 
    }
    private static void generateFile(File f, String str) throws IOException {
        BufferedWriter br = new BufferedWriter(new FileWriter(f));
        br.write(str);
        br.close();
    }
}
